﻿using BCCommon;
using BCCommon.AliPayAOPSDK.Util;
using BCCommon.Enums;
using BCCommon.Exceptions;
using BCCommon.Extensions;
using BCCommon.PaymentEnums;
using BCData.Common.Payment.Payment;
using BCDto.Common.Payment.Payment;
using BCDto.Common.Payment.PaymentRecord;
using BCDto.Sim.Admin.Admin;
using BCDto.Website.User;
using BCEntity.Common.Payment.Payment;
using BCService.Common.Payment.Payment.AliPayModel;
using BCService.Common.Wallet;
using BCService.Utils;
using BCService.Website.User;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;

namespace BCService.Common.Payment.Payment
{
    public class AlipayService : IAlipayService
    {
        private static readonly string CharSet = "utf-8"; // 字符集
        private static readonly string SignType = "RSA2"; // 加密类型

        private readonly string GatewayUrl; // 支付宝请求地址
        
        /// <summary>
        /// 支付渠道类型
        /// </summary>
        public PaymentChannelType ChannelType { get; set; }

        /// <summary>
        /// 应用类型
        /// </summary>
        public SourceAppType AppType { get; set; }

        /// <summary>
        /// 操作系统类型
        /// </summary>
        public SourceOSType OSType { get; set; }

        private readonly IConfiguration configuration;
        private readonly IPaymentRecordData paymentRecordData;
        private readonly IUserService userService;
        private readonly IWalletService walletService;
        private readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings
        {
            ContractResolver = new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy { ProcessDictionaryKeys = false } },
            Converters = new List<JsonConverter> {
                new StringEnumConverter { AllowIntegerValues = true },
                new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeLocal, DateTimeFormat = "yyyy-MM-dd HH:mm:ss" }
            },
            NullValueHandling = NullValueHandling.Ignore
        };

        public AlipayService(IConfiguration configuration,IPaymentRecordData paymentRecordData, IWalletService walletService, IUserService userService)
        {
            this.configuration = configuration;
            this.paymentRecordData = paymentRecordData;
            this.walletService = walletService;
            this.userService = userService;

            this.GatewayUrl = configuration["Alipay:GATEWAYURL"];
        }

        public decimal? GetBalance(UserDto userDto)
        {
            return null;
        }

        public decimal? GetLimit(UserDto userDto)
        {
            return null;
        }

        public decimal? GetAgentBalance(long agentRecordId)
        {
            return null;
        }

        public decimal? GetAgentLimit(long agentRecordId)
        {
            return null;
        }

        #region 尝试支付
        public PaymentDto TryPay(SourceAppType appType, FlowType orderType, string subject, string referenceNumber, SourceOSType osType, SourceDeviceType deviceType, string deviceId, IDictionary<string, string> parameters, decimal amount, SourcePayerType? payer,UserDto userDto)
        {
            decimal newAmount = Math.Round(amount, 2);

            PaymentRecordEntity entity = this.paymentRecordData.Create(this.ChannelType, orderType.ToString(),subject, referenceNumber, newAmount, userDto.UserId, appType, osType, payer, configuration[$"Alipay:{AppType}:APP_ID"]);

            bool isWindows = deviceType == SourceDeviceType.Web | deviceType == SourceDeviceType.PC;

            AlipayBizContent bizContent = new AlipayBizContent
            {
                Subject = subject,
                OutTradeNo = entity.PaymentRecordId.ToString(),
                TotalAmount = newAmount.ToString("0.00"),
                ProductCode = isWindows ? "FAST_INSTANT_TRADE_PAY" : "QUICK_MSECURITY_PAY"
            };

            string method = isWindows ? "alipay.trade.page.pay" : "alipay.trade.app.pay";

            string requestParameters = this.CreateParameters(method, bizContent,entity.PaymentRecordId);

            if (isWindows)
            {
                requestParameters = $"{GatewayUrl}?{requestParameters}";
            }

            this.paymentRecordData.SetAsRequireAction(entity.PaymentRecordId);

            return new PaymentDto
            {
                PaymentRecordId = entity.PaymentRecordId,
                OrderType = orderType,
                ReferenceNumber = referenceNumber,
                PayChannelType = this.ChannelType,
                OriginalAmount = newAmount,
                Discount = 0,
                PaidAmount = newAmount,
                Result = PaymentResultType.RequireAction,
                ActionArguments = requestParameters
            };
        }

        public PaymentDto AgentTryPay(SourceAppType appType, FlowType orderType, string subject, string referenceNumber, SourceOSType osType,
            SourceDeviceType deviceType, string deviceId, IDictionary<string, string> parameters, decimal amount, SourcePayerType? payer,
            AdminDto admin)
        {
            decimal newAmount = Math.Round(amount, 2);

            PaymentRecordEntity entity = this.paymentRecordData.Create(this.ChannelType, orderType.ToString(), subject, referenceNumber,
                newAmount, null, appType, osType, payer, configuration[$"Alipay:{AppType}:APP_ID"]);

            bool isWindows = deviceType == SourceDeviceType.Web | deviceType == SourceDeviceType.PC;

            AlipayBizContent bizContent = new AlipayBizContent
            {
                Subject = subject,
                OutTradeNo = entity.PaymentRecordId.ToString(),
                TotalAmount = newAmount.ToString("0.00"),
                ProductCode = isWindows ? "FAST_INSTANT_TRADE_PAY" : "QUICK_MSECURITY_PAY"
            };

            string method = isWindows ? "alipay.trade.page.pay" : "alipay.trade.app.pay";

            string requestParameters = this.CreateParameters(method, bizContent, entity.PaymentRecordId);

            if (isWindows)
            {
                requestParameters = $"{GatewayUrl}?{requestParameters}";
            }

            this.paymentRecordData.SetAsRequireAction(entity.PaymentRecordId);

            return new PaymentDto
            {
                PaymentRecordId = entity.PaymentRecordId,
                OrderType = orderType,
                ReferenceNumber = referenceNumber,
                PayChannelType = this.ChannelType,
                OriginalAmount = newAmount,
                Discount = 0,
                PaidAmount = newAmount,
                Result = PaymentResultType.RequireAction,
                ActionArguments = requestParameters
            };
        }

        #endregion

        #region 生成付款码
        public PaymentQRCodeDto GenerateQRCode(SourceAppType appType, FlowType orderType, string subject, string referenceNumber, SourceOSType osType, SourceDeviceType deviceType, string deviceId, IDictionary<string, string> parameters, decimal amount, SourcePayerType? payer, UserDto userDto)
        {
            decimal newAmount = Math.Round(amount, 2);

            PaymentRecordEntity entity = this.paymentRecordData.Create(this.ChannelType, orderType.ToString(), referenceNumber,subject, newAmount, userDto.UserId, appType, osType, payer, configuration[$"Alipay:{AppType}:APP_ID"]);

            AlipayBizContent bizContent = new AlipayBizContent
            {
                Subject = subject,
                OutTradeNo = entity.PaymentRecordId.ToString(),
                TotalAmount = newAmount.ToString("0.00"),
                TimeoutExpress = "10m"
            };
            
            string requestParameters = this.CreateParameters("alipay.trade.precreate", bizContent, entity.PaymentRecordId);

            using (HttpClient httpClient = new HttpClient())
            {
                string requestUrl = string.Format("{0}?{1}", GatewayUrl, requestParameters);

                using (HttpResponseMessage responseMessage = httpClient.GetAsync(requestUrl).Result)
                {
                    //支付宝HTTPS返回报文无需验签
                    string jsonString = responseMessage.EnsureSuccessStatusCode().Content.ReadAsStringAsync().GetAwaiter().GetResult();

                    dynamic result = JsonConvert.DeserializeObject(jsonString);

                    if (result.alipay_trade_precreate_response.msg == "Success")
                    {
                        this.paymentRecordData.SetAsRequireAction(entity.PaymentRecordId);

                        return new PaymentQRCodeDto
                        {
                            PayChannelType = this.ChannelType,
                            Token = result.alipay_trade_precreate_response.qr_code,
                            ExpireTime = DateTime.Now.AddMinutes(5),
                            OutTradeNo = bizContent.OutTradeNo
                        };
                    }
                    else
                    {
                        string failRemark = result.alipay_trade_precreate_response.sub_msg;
                        this.paymentRecordData.SetAsFailed(entity.PaymentRecordId, failRemark);

                        throw new ArgumentException("无法生成支付二维码。");
                    }
                }
            }
        }
        #endregion

        public PaymentQRCodeDto AgentGenerateQRCode(SourceAppType appType, FlowType orderType, string subject,
string referenceNumber, SourceOSType osType, SourceDeviceType deviceType, string deviceId,
IDictionary<string, string> parameters, decimal amount, SourcePayerType? payer, AdminDto admin)
        {
            throw new NotImplementedException();
        }

        #region 提现转账
        public decimal Transfer(SourceAppType appType, SourceOSType osType, long recordId, decimal transferAmount, long userId, string open_userid, UserDto userDto)
        {
            var wallet = walletService.GetWalletByUserId(userId);
            if (wallet.AlipayAuthInfo == null)
            {
                throw new ArgumentException("当前提现用户未授权，非法操作！");
            }
            //验证是否在钱包授权过
            dynamic wallet_result = JsonConvert.DeserializeObject(wallet.AlipayAuthInfo.ToString());

            //如未授权说明非法提现
            string alipay_user_id = wallet_result.alipay_user_userinfo_share_response.alipay_user_id;
            if (alipay_user_id == open_userid)
            {
                AlipayBizContent bizContent = new AlipayBizContent
                {
                    OutBizNo = recordId.ToString("0000000000"),
                    PayeeType = "ALIPAY_USERID",
                    PayeeAccount = open_userid,
                    Amount = transferAmount.ToString("0.00")
                };
                string requestParameters = this.CreateParameters("alipay.fund.trans.toaccount.transfer", bizContent, null);
                using (HttpClient httpClient = new HttpClient())
                {
                    string requestUrl = string.Format("{0}?{1}", GatewayUrl, requestParameters);

                    using (HttpResponseMessage responseMessage = httpClient.GetAsync(requestUrl).Result)
                    {
                        string jsonString = responseMessage.EnsureSuccessStatusCode().Content.ReadAsStringAsync().GetAwaiter().GetResult();
                        dynamic result = JsonConvert.DeserializeObject(jsonString);
                        // TODO: 验证签名，重要!!!。
                        if (result.alipay_fund_trans_toaccount_transfer_response.msg == "Success")
                        {
                            return transferAmount;
                        }
                        else
                        {
                            throw new ArgumentException("将提现/转账提交到支付宝时发生错误，你可能需要通过支付宝后台确认提现状态。");
                        }
                    }
                }
            }
            throw new ArgumentException("当前提现用户和授权用户不一致，非法操作！");
        }
        #endregion

        #region 退款
        public decimal Refund(long adminId, string adminFullName, long recordId, decimal refundAmount)
        {
            PaymentRecordEntity payment = this.paymentRecordData.GetPaymentRecordByPaymentRecordId(recordId);

            if (payment == null)
            {
                throw new ArgumentException("无法找到匹配的付款记录，无法进行退款。");
            }

            decimal refundedAmount = this.paymentRecordData.GetPaymentRecordsByReferenceNumber(payment.OrderType.AsEnum<FlowType>(), payment.ReferenceNumber).Where(p => p.Status == PaymentResultType.Success.ToString()).Sum(p => p.Amount);

            if ((-refundedAmount + refundAmount) > payment.Amount)
            {
                throw new ArgumentException("可退余额不足，无法进行退款。");
            }

            decimal newAmount = Math.Round(refundAmount, 2);

            PaymentRecordEntity refund = this.paymentRecordData.Create(this.ChannelType, payment.OrderType.ToString(),"退款", payment.ReferenceNumber, -newAmount, payment.UserId, payment.AppType.AsEnum<SourceAppType>(), payment.OSType.AsEnum<SourceOSType>(), (SourcePayerType?)payment.Payer, payment.AppId, adminId, adminFullName, PaymentOperationType.Refund.ToString(), SourceFlowDirectionType.Outlay);

            AlipayBizContent bizContent = new AlipayBizContent
            {
                OutTradeNo = payment.PaymentRecordId.ToString(),
                RefundAmount = newAmount.ToString("0.00")
            };

            string requestParameters = this.CreateParameters("alipay.trade.refund", bizContent, refund.PaymentRecordId);

            using (HttpClient httpClient = new HttpClient())
            {
                string requestUrl = string.Format("{0}?{1}", GatewayUrl, requestParameters);

                using (HttpResponseMessage responseMessage = httpClient.GetAsync(requestUrl).Result)
                {
                    string jsonString = responseMessage.EnsureSuccessStatusCode().Content.ReadAsStringAsync().GetAwaiter().GetResult();

                    dynamic result = JsonConvert.DeserializeObject(jsonString);

                    // TODO: 验证签名，重要!!!。
                    if (result.alipay_trade_refund_response.msg == "Success")
                    {
                        this.paymentRecordData.SetAsSuccess(refund.PaymentRecordId);

                        return payment.Amount - -refundedAmount - refundAmount;
                    }
                    else
                    {
                        string failRemark = result.alipay_trade_precreate_response.sub_msg;
                        this.paymentRecordData.SetAsFailed(refund.PaymentRecordId, failRemark);

                        throw new ArgumentException("将退款请求提交到支付宝时发生错误，你可能需要先通过支付宝后台确认退款状态。");
                    }
                }
            }
        }
        #endregion

        #region 下载对账单
        public string DownloadBill(DateTime billDate, AliPayBillType billType)
        {
            AlipayBizContent bizContent = new AlipayBizContent
            {
                BillDate = billDate.ToString("yyyy-MM-dd"),
                BillType = billType.ToString()
            };

            string requestParameters = this.CreateParameters("alipay.data.dataservice.bill.downloadurl.query", bizContent, null);
            using (HttpClient httpClient = new HttpClient())
            {
                string requestUrl = string.Format("{0}?{1}", GatewayUrl, requestParameters);

                using (HttpResponseMessage responseMessage = httpClient.GetAsync(requestUrl).Result)
                {
                    string jsonString = responseMessage.EnsureSuccessStatusCode().Content.ReadAsStringAsync().GetAwaiter().GetResult();
                    dynamic result = JsonConvert.DeserializeObject(jsonString);
                    // TODO: http://dwbillcenter.alipay.com/downloadBillFile.resource?bizType=trade&userId=20883315106417300156&fileType=csv.zip&bizDates=20200111&downloadFileName=20883315106417300156_20200111.csv.zip&fileId=%2Ftrade%2F20883315106417300156%2F20200111.csv.zip&timestamp=1581928446&token=e6ff8e246606719d802e8adc6e5e82d4
                    if (result.alipay_data_dataservice_bill_downloadurl_query_response.msg == "Success")
                    {
                        return result.alipay_data_dataservice_bill_downloadurl_query_response.bill_download_url;
                    }
                    else if (result.alipay_data_dataservice_bill_downloadurl_query_response.msg == "Business Failed")
                    {
                        return string.Empty;
                    }
                    else
                    {
                        throw new ArgumentException("支付宝查询对账单时发生错误。");
                    }
                }
            }
        }
        #endregion

        #region 同步验签--例如app调起支付宝，支付成功后使用App返回的支付结果的验签

        public PaymentRecordDto SyncCheckSign(IDictionary<string, string> parameters)
        {
            if (!AlipaySignature.RSACheckV1(parameters, configuration["Alipay:ZhiFuBao_PublicKey"], CharSet, SignType, false, true))
            {
                throw new ArgumentException("支付宝验签失败");
            }

            AlipayTradeAppPayResponseDto alipayTradeAppPayResponseDto = JsonConvert.DeserializeObject<AlipayTradeAppPayResponseDto>(parameters["alipay_trade_app_pay_response"], JsonSerializerSettings);

            PaymentRecordEntity entity = this.paymentRecordData.GetPaymentRecordByPaymentRecordId(long.Parse(alipayTradeAppPayResponseDto.OutTradeNo));
            PaymentRecordEntity resultEntity = null;
            if (entity == null)
            {
                throw new ArgumentException("找不到指定的付款订单。");
            }

            if (entity.Amount != decimal.Parse(alipayTradeAppPayResponseDto.TotalAmount))
            {
                throw new ArgumentException("通知的金额与订单金额不符。");
            }

            dynamic result = this.GetAlipayRecordInfo(alipayTradeAppPayResponseDto.OutTradeNo, alipayTradeAppPayResponseDto.TradeNo);
            if (result.alipay_trade_query_response.code != "10000")
            {
                throw new ArgumentException("获取阿里支付交易信息失败");
            }
            if (result.alipay_trade_query_response.trade_status != "TRADE_SUCCESS")
            {
                throw new ArgumentException("支付失败");
            }
            if (configuration["Alipay:ZhiFuBao_SellerId"] != alipayTradeAppPayResponseDto.SellerId)
            {
                throw new ArgumentException("对比支付人信息失败");
            }
            if (alipayTradeAppPayResponseDto.AppId != configuration[$"Alipay:{AppType}:APP_ID"])
            {
                throw new ArgumentException("应用Id与付款应用Id不相同");
            }
            //异步回调不能修改验签时间，需要和同步验签的逻辑相反。否则数据会重复。
            resultEntity = entity;
            //while (resultEntity == null)
            //{
            //    resultEntity = this.paymentRecordData.SetAsSignTime(entity.PaymentRecordId);
            //}
            return resultEntity.As<PaymentRecordDto>();
        }
        #endregion

        #region 接收通知
        public ReceiveNotificationDto ReceiveNotification(IDictionary<string, string> parameters, out PaymentDto payment)
        {
            long paymentRecordId = long.Parse(parameters["out_trade_no"]);

            PaymentRecordEntity entity = this.paymentRecordData.GetPaymentRecordByPaymentRecordId(paymentRecordId);

            if (entity == null)
            {
                throw new ArgumentException("找不到指定的付款订单。");
            }

            dynamic response = this.GetAlipayRecordInfo(parameters["out_trade_no"], parameters["trade_no"]).alipay_trade_query_response;

            if (response.code != "10000")
            {
                throw new ArgumentException("获取支付宝交易信息失败。");
            }

            if (response.trade_status == "TRADE_CLOSED")
            {
                //异步通知类型退款和交易关闭都是TRADE_CLOSED,退款通知时，refund_fee返回总退款金额,单位为元，支持两位小数
                if (response.refund_fee > 0)
                {
                    entity = this.paymentRecordData.UpdateRefundOperationType(paymentRecordId).GetAwaiter().GetResult();
                }
                else
                {

                    string failRemark = response.alipay_trade_precreate_response.sub_msg;
                    entity = this.paymentRecordData.SetAsFailed(paymentRecordId, failRemark);
                }
            }

            if (response.trade_status == "TRADE_SUCCESS")
            {
                if (parameters["seller_id"] == configuration["Alipay:ZhiFuBao_SellerId"] && parameters["app_id"] == configuration[$"Alipay:{AppType}:APP_ID"])
                {
                    // 异步回调不能修改验签时间，需要和同步验签的逻辑相反。否则数据会重复。
                    entity = this.paymentRecordData.SetAsSuccess(paymentRecordId);
                }
                else
                {
                    entity = this.paymentRecordData.SetAsToBeConfirmed(paymentRecordId);
                }
            }

            if (response.trade_status == "TRADE_FINISHED")
            {
                entity = this.paymentRecordData.SetAsToBeConfirmed(paymentRecordId);
            }

            payment = entity.TransformTo<PaymentDto>();

            return new ReceiveNotificationDto
            {
                StatusCode = 200,
                ContentType = "text/plain",
                ReturnString = "success"
            };
        }
        #endregion

        #region 创建App授权登录
        public IDictionary<string, string> CreateAppAuthLogin(SourceAppType appType, SourceOSType osType,UserDto userDto)
        {
            SortedDictionary<string, string> dictionary = new SortedDictionary<string, string>();

            dictionary.Add("apiname", "com.alipay.account.auth");
            dictionary.Add(AlipayParameter.METHOD, "alipay.open.auth.sdk.code.get");
            dictionary.Add(AlipayParameter.APP_ID, configuration[$"Alipay:{AppType}:APP_ID"]);
            dictionary.Add("app_name", "mc");
            dictionary.Add("biz_type", "openservice");
            dictionary.Add("pid", configuration["Alipay:ZhiFuBao_SellerId"]);
            dictionary.Add("product_id", "APP_FAST_LOGIN");
            dictionary.Add("scope", "kuaijie");
            dictionary.Add("target_id", userDto.UserId.ToString());
            dictionary.Add("auth_type", "AUTHACCOUNT");
            dictionary.Add("sign_type", SignType);
            //签名

            string sign = WebUtility.UrlEncode(AlipaySignature.RSASignCharSet(string.Join("&", dictionary.Select(d => string.Concat(d.Key, "=", d.Value))), configuration[$"Alipay:{AppType}:Private_Key"], CharSet, false, SignType));
            dictionary.Add(AlipayParameter.SIGN, sign);

            return new Dictionary<string, string>
            {
                { "auth_info", string.Join("&", dictionary.Select(p => string.Format("{0}={1}", p.Key, p.Value))) }
            };
        }
        #endregion

        /// <summary>
        /// 获取阿里支付交易信息--outTradeNo与tradeNo同时存在，已支付宝交易号为准
        /// </summary>
        /// <param name="outTradeNo">商户订单号</param>
        /// <param name="tradeNo">支付宝交易号</param>
        /// <returns>查询结果集</returns>
        public dynamic GetAlipayRecordInfo(string outTradeNo, string tradeNo)
        {
            AlipayBizContent bizContent = new AlipayBizContent
            {
                OutTradeNo = outTradeNo,
                TradeNo = tradeNo
            };
            if (!long.TryParse(outTradeNo, out long paymentRecordId))
            {
                throw new ArgumentException("支付记录编号错误");
            }
            string requestParameters = CreateParameters("alipay.trade.query", bizContent, paymentRecordId);

            using (HttpClient httpClient = new HttpClient())
            {
                string requestUrl = string.Format("{0}?{1}", GatewayUrl, requestParameters);
                //支付宝HTTPS返回报文无需验签
                using (HttpResponseMessage responseMessage = httpClient.GetAsync(requestUrl).Result)
                {
                    string jsonString = responseMessage.EnsureSuccessStatusCode().Content.ReadAsStringAsync().GetAwaiter().GetResult();
                    dynamic result = JsonConvert.DeserializeObject(jsonString);
                    string signContent = JsonConvert.SerializeObject(result.alipay_trade_query_response);
                    string sign = result.sign;

                    return result;
                }
            }
        }

        /// <summary>
        /// 创建请求参数，合并公共请求参数和各方法的名称与请求参数
        /// </summary>
        /// <param name="method">各请求方法名称</param>
        /// <param name="bizContent">各请求独立参数</param>
        /// <param name="paymentRecordId"></param>
        /// <returns></returns>
        private string CreateParameters(string method, IAlipayBizContent bizContent, long? paymentRecordId)
        {
            SortedDictionary<string, string> dictionary = new SortedDictionary<string, string>();
            dictionary.Add(AlipayParameter.APP_ID, configuration[$"Alipay:{AppType}:APP_ID"]);
            dictionary.Add(AlipayParameter.METHOD, method);
            dictionary.Add(AlipayParameter.FORMAT, "json");
            dictionary.Add(AlipayParameter.CHARSET, CharSet);
            dictionary.Add(AlipayParameter.SIGN_TYPE, SignType);
            dictionary.Add(AlipayParameter.TIMESTAMP, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            dictionary.Add(AlipayParameter.VERSION, "1.0");
            if (paymentRecordId != null)
            {
                string formatValue = string.Format(configuration["PayNotify:postUrl"], this.ChannelType.ToString(), paymentRecordId);
                dictionary.Add(AlipayParameter.NOTIFY_URL, formatValue);
            }
            dictionary.Add(AlipayParameter.BIZ_CONTENT, bizContent.Serialize());
            string sign = AlipaySignature.RSASignCharSet(string.Join("&", dictionary.Select(d => string.Concat(d.Key, "=", d.Value))), configuration[$"Alipay:{AppType}:Private_Key"], CharSet, false, SignType);
            dictionary.Add(AlipayParameter.SIGN, sign);
            return string.Join("&", dictionary.Select(p => string.Format("{0}={1}", p.Key, WebUtility.UrlEncode(p.Value))));
        }

        private string GetAuthToken(string code)
        {
            SortedDictionary<string, string> dictionary = new SortedDictionary<string, string>();
            dictionary.Add(AlipayParameter.APP_ID, configuration[$"Alipay:{AppType}:APP_ID"]);
            dictionary.Add(AlipayParameter.METHOD, "alipay.system.oauth.token");
            dictionary.Add(AlipayParameter.FORMAT, "JSON");
            dictionary.Add(AlipayParameter.CHARSET, CharSet);
            dictionary.Add(AlipayParameter.SIGN_TYPE, SignType);
            dictionary.Add(AlipayParameter.TIMESTAMP, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            dictionary.Add(AlipayParameter.VERSION, "1.0");
            dictionary.Add("grant_type", "authorization_code");
            dictionary.Add("code", code);

            string sign = AlipaySignature.RSASignCharSet(string.Join("&", dictionary.Select(d => string.Concat(d.Key, "=", d.Value))), configuration[$"Alipay:{AppType}:Private_Key"], CharSet, false, SignType);

            dictionary.Add(AlipayParameter.SIGN, sign);

            string requestParameters = string.Join("&", dictionary.Select(p => string.Format("{0}={1}", p.Key, WebUtility.UrlEncode(p.Value))));
            using (HttpClient httpClient = new HttpClient())
            {
                string requestUrl = string.Format("{0}?{1}", GatewayUrl, requestParameters);

                using (HttpResponseMessage responseMessage = httpClient.GetAsync(requestUrl).Result)
                {
                    string jsonString = responseMessage.EnsureSuccessStatusCode().Content.ReadAsStringAsync().GetAwaiter().GetResult();
                    dynamic result = JsonConvert.DeserializeObject(jsonString);
                    try
                    {
                        return result.alipay_system_oauth_token_response.access_token;
                    }
                    catch (Exception)
                    {
                        throw new ArgumentException("获取AuthToken时候发生异常");
                    }
                }
            }
        }

        public IDictionary<string, object> AuthLoginInfo(string auth_code, SourceAppType appType, SourceOSType osType,UserDto userDto)
        {
            string result_token = GetAuthToken(auth_code);
            SortedDictionary<string, string> dictionary = new SortedDictionary<string, string>();
            dictionary.Add(AlipayParameter.APP_ID, configuration[$"Alipay:{AppType}:APP_ID"]);
            dictionary.Add(AlipayParameter.METHOD, "alipay.user.userinfo.share");
            dictionary.Add(AlipayParameter.CHARSET, CharSet);
            dictionary.Add(AlipayParameter.SIGN_TYPE, SignType);
            dictionary.Add(AlipayParameter.TIMESTAMP, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            dictionary.Add(AlipayParameter.VERSION, "1.0");
            dictionary.Add("auth_token", result_token);
            //签名
            string sign = AlipaySignature.RSASignCharSet(string.Join("&", dictionary.Select(d => string.Concat(d.Key, "=", d.Value))), configuration[$"Alipay:{AppType}:Private_Key"], CharSet, false, SignType);
            dictionary.Add(AlipayParameter.SIGN, sign);

            string requestParameters = string.Join("&", dictionary.Select(p => string.Format("{0}={1}", p.Key, WebUtility.UrlEncode(p.Value))));
            using (HttpClient httpClient = new HttpClient())
            {
                string requestUrl = string.Format("{0}?{1}", GatewayUrl, requestParameters);

                using (HttpResponseMessage responseMessage = httpClient.GetAsync(requestUrl).Result)
                {
                    string jsonString = responseMessage.EnsureSuccessStatusCode().Content.ReadAsStringAsync().GetAwaiter().GetResult();

                    //更新钱包授权信息
                    walletService.ChangeAliPayAuthInfo(userDto.UserId, jsonString);
                    object result = JsonConvert.DeserializeObject(jsonString);
                    return new Dictionary<string, object>
                    {
                        { "auth_login_info", result },
                        {"channel_id", ChannelType.ToString() }
                    };
                }
            }
        }

        public bool ConfirmPayValidation(long paymentRecordId, string referenceNumber, string password, UserDto userDto)
        {
            throw new ArgumentException("确认支付仅支持线下支付、余额支付及银行卡支付");
        }

        public PaymentRecordDto Synchronize(long paymentRecordId, PaymentSynchronizeRequestDto requestDto)
        {
            PaymentRecordEntity entity = this.paymentRecordData.GetPaymentRecordByPaymentRecordId(paymentRecordId);

            if (entity == null)
            {
                throw new ObjectNotFoundException();
            }

            if (entity.Status != PaymentResultType.Success.ToString() && entity.CheckSignTime == null)
            {
                dynamic response = this.GetAlipayRecordInfo(paymentRecordId.ToString(), null)?.alipay_trade_query_response;

                if (response == null)
                {
                    throw new Exception("获取支付宝交易信息失败。");
                }

                if (response.code != "10000")
                {
                    throw new Exception("获取支付宝交易信息失败。");
                }

                if (response.trade_status != "TRADE_SUCCESS")
                {
                    throw new Exception("支付失败。");
                }

                if ((decimal)response.total_amount != entity.Amount)
                {
                    throw new Exception("支付宝实际支付金额与原订单不符。");
                }

                entity = this.paymentRecordData.SetAsSuccess(paymentRecordId);
            }

            return entity.As<PaymentRecordDto>();
        }
    }
}
